/**
 * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef OHOS_GPU_RENDER_THREAD_H
#define OHOS_GPU_RENDER_THREAD_H
#include "EglRenderContext.h"
#include "GPUImageFilter.h"
#include "OpenGlUtils.h"
#include "napi_util.h"
#include <EGL/egl.h>
#include <multimedia/image_framework/image_pixel_map_mdk.h>
#include <native_image/native_image.h>
#include <native_vsync/native_vsync.h>
#include <queue>
#include <thread>

class GPURenderThread {
public:
    GPURenderThread();
    ~GPURenderThread();
    void start(void *nativeWindow, uint64_t width, uint64_t height);
    void stop();
    void releaseResources();
    void setFilter(std::shared_ptr<GPUImageFilter> filter);
    void setCallback(std::shared_ptr<CallbackListener> callback);
    uint64_t getSurfaceId();
    void updateXComponentSize(int width, int height);
    void savePixelMap(std::shared_ptr<CallbackListener> callback);
    void dumpImageRequest(const std::string &path);
    void dumpImage(void *data, int width, int height);
    void runOnDraw(std::function<void()> task);
    void setOrientation(Rotation rotation, bool flipX, bool flipY);
    const float CUBE[8] = {
        -1.0f,
        -1.0f,
        1.0f,
        -1.0f,
        -1.0f,
        1.0f,
        1.0f,
        1.0f,
    };
    float glCubeBuffer[8] = {
        -1.0f,
        -1.0f,
        1.0f,
        -1.0f,
        -1.0f,
        1.0f,
        1.0f,
        1.0f,
    };
    float glTextureBuffer[8] = {
        1.0f,
        1.0f,
        1.0f,
        0.0f,
        0.0f,
        1.0f,
        0.0f,
        0.0f,
    };

private:
    std::atomic<bool> running{false};
    std::atomic<bool> initialized; // 线程是否初始化完成
    std::mutex taskMutex;
    std::mutex filterMutex;
    std::thread renderThread;
    std::shared_ptr<CallbackListener> filterOutputCb = nullptr;
    GLuint textureOES = OpenGlUtils::NO_TEXTURE;
    uint64_t surfaceId = 0;
    OH_NativeImage *nativeImage = nullptr;
    OH_OnFrameAvailableListener onFrameAvailableListener;
    std::shared_ptr<GPUImageFilter> filter = nullptr;
    EGLSurface eglSurface;
    int outputWidth = 0;
    int outputHeight = 0;

    static void onNativeImageFrameAvailable(void *data);
    void notifyFrameAvailable();
    void adjustImageScaling();
    float addDistance(float coordinate, float distance);
    void renderFrame();

    void threadMainLoop();
    bool initRenderContext(void *nativeWindow, uint64_t width, uint64_t height);
    void destroyRenderContext();

    // 在渲染线程中执行资源的创建与清理
    bool createGLResources();
    void cleanGLResources();

    bool createNativeImage();
    void destroyNativeImage();
    void configTexture();
    void readPixelFromFBO();
    void runPendingOnDrawTasks();

    std::atomic<int> availableFrameCnt{0};
    std::condition_variable wakeUpCond;
    mutable std::mutex wakeUpMutex;
    std::atomic<bool> isNeedDump{false};
    int64_t frameId = 0;
    std::string dumpPath;
    std::queue<std::function<void()>> tasks;
    std::unique_ptr<EglRenderContext> renderContext;
    bool isNeedSavePixelMap = false;
};
#endif // OHOS_GPU_RENDER_THREAD_H
